package com.edu.activiti.test;

import org.activiti.engine.*;
import org.activiti.engine.history.HistoricActivityInstance;
import org.activiti.engine.history.HistoricActivityInstanceQuery;
import org.activiti.engine.repository.Deployment;
import org.activiti.engine.repository.ProcessDefinition;
import org.activiti.engine.repository.ProcessDefinitionQuery;
import org.activiti.engine.runtime.ProcessInstance;
import org.activiti.engine.task.Task;
import org.apache.commons.io.IOUtils;
import org.junit.Test;

import java.io.*;
import java.util.List;
import java.util.Objects;
import java.util.zip.ZipInputStream;

/**
 * @author wu大人
 * @version 1.0
 * @date 2021/6/25 18:11
 */
public class ActivitiDemo {
    /**
     * 创建流程实例
     */
    @Test
    public void testProcessEngineDeployment() {
        //1.创建ProcessEngine
        ProcessEngine defaultProcessEngine = ProcessEngines.getDefaultProcessEngine();
        //2.获取RepositoryService
        RepositoryService repositoryService = defaultProcessEngine.getRepositoryService();
        //3.使用Service进行流程的部署，定义一个流程的名字，把bpmn和png部署到数据库中
        Deployment deployment = repositoryService.createDeployment()
                .addClasspathResource("bpmn/evection.bpmn")
                .addClasspathResource("bpmn/evection.png")
                .name("出差流程申请")
                .deploy();
        //4.输出部署信息
        System.out.println("流程部署ID" + deployment.getId());
        System.out.println("流程部署名字" + deployment.getName());
    }

    /**
     * 启动流程实例
     */
    @Test
    public void testStartProcess() {
        //1.创建ProcessEngine
        ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
        //2.获取RuntimeService
        RuntimeService runtimeService = processEngine.getRuntimeService();
        //3.获取流程定义的id启动实例
        ProcessInstance instance = runtimeService.startProcessInstanceByKey("myEvection");
        //4.输出内容
        System.out.println("流程定义ID" + instance.getProcessDefinitionId());
        System.out.println("流程实例ID" + instance.getId());
        System.out.println("当前活动的ID" + instance.getActivityId());
    }

    /**
     * 查询个人待执行的任务
     */
    @Test
    public void testFindPersonalTaskList() {
        //1.获取流程引擎
        ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
        //2.获取taskService
        TaskService taskService = processEngine.getTaskService();
        //3.根据流程key和任务的负责人查询任务
        List<Task> list = taskService.createTaskQuery()
                .processDefinitionKey("myEvection")//流程的key
                .taskAssignee("zhangsan")//要查询的流程负责人
                .list();
        for (Task task : list) {
            System.out.println("流程实例ID=" + task.getProcessDefinitionId());
            System.out.println("任务ID=" + task.getId());
            System.out.println("任务负责人=" + task.getAssignee());
            System.out.println("任务名称=" + task.getName());
        }
    }

    /**
     * 完成任务
     */
    @Test
    public void completTask() {
        //获取流程引擎
        ProcessEngine defaultProcessEngine = ProcessEngines.getDefaultProcessEngine();
        //获取service
        TaskService taskService = defaultProcessEngine.getTaskService();
        //根据查出来的任务ID来完成任务
//        taskService.complete("2505");
        // 获取jerry - myEvection 对应的任务
        Task task = taskService.createTaskQuery()
                .processDefinitionKey("myEvection")//唯一标识符不变
//                .taskAssignee("jack")//完成Jack的任务
//                .taskAssignee("jerry")//完成jerry的任务
                .taskAssignee("rose")//完成rose的任务
                .singleResult();
        //输出任务
        System.out.println("流程实例ID=" + task.getProcessDefinitionId());
        System.out.println("任务ID=" + task.getId());
        System.out.println("任务负责人=" + task.getAssignee());
        System.out.println("任务名称=" + task.getName());
        //完成jerry的任务
        taskService.complete(task.getId());
    }

    /**
     * 使用ZIP来批量部署流程
     */
    @Test
    public void deployProcessByZIP() {
        //获取流程引擎
        ProcessEngine processEnginerocessEngine = ProcessEngines.getDefaultProcessEngine();
        //获取RepositoryService
        RepositoryService repositoryService = processEnginerocessEngine.getRepositoryService();
        //流程部署操作
        Deployment deploy = repositoryService.createDeployment()
                //获取相对路径：this.getClass().getClassLoader().getResourceAsStream("bpmn/evection.zip")
                //获取相对路径：Objects.requireNonNull(this.getClass().getClassLoader().getResourceAsStream("bpmn/evection.zip"))
                .addZipInputStream(new ZipInputStream(Objects.requireNonNull(this.getClass().getClassLoader().getResourceAsStream("bpmn/evection.zip"))))
                .deploy();
        System.out.println("流程部署ID\t" + deploy.getId());
        System.out.println("流程部署名称\t" + deploy.getName());
    }

    /**
     * 查询流程定义信息
     * ACT_GE_BYTEARRAY
     * ACT_RE_DEPLOYMENT
     * ACT_RE_PROCDEF
     */
    @Test
    public void queryProcessDefinition() {
        //获取流程引擎
        ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
        //获取Service(RepositoryService)
        RepositoryService repositoryService = processEngine.getRepositoryService();
        // 获取ProcessDefinitionQuery对象
        ProcessDefinitionQuery processDefinitionQuery = repositoryService.createProcessDefinitionQuery();
        //查询当前所有流程的定义
        List<ProcessDefinition> processDefinitions = processDefinitionQuery
                .processDefinitionKey("myEvection")//通过key进行查询
                .orderByProcessDefinitionVersion()//按照version排序
                .desc()//倒序排列
                .list();//返回全部查询结果
        //输出查询内容信息
        for (ProcessDefinition processDefinition : processDefinitions) {
            System.out.println("流程定义ID=" + processDefinition.getId());
            System.out.println("流程定义名称=" + processDefinition.getName());
            System.out.println("流程定义版本号=" + processDefinition.getVersion());
            System.out.println("流程定义的Key=" + processDefinition.getKey());
            System.out.println("流程定义的部署ID=" + processDefinition.getDeploymentId());
        }
    }

    /**
     * 流程部署信息删除
     * ACT_GE_BYTEARRAY
     * ACT_RE_DEPLOYMENT
     * ACT_RE_PROCDEF
     * 注意：当前流程如果并没有完成，想要删除的话就要使用特殊模式，原理就是级联删除
     */
    @Test
    public void deleteDeployment() {
        // 流程部署id
        String deploymentId = "1";
        ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
        // 通过流程引擎获取repositoryService
        RepositoryService repositoryService = processEngine.getRepositoryService();
        //删除流程定义，如果该流程定义已有流程实例启动则删除时出错
//        repositoryService.deleteDeployment(deploymentId);
        //设置true 级联删除流程定义，即使该流程有流程实例启动也可以删除，设置为false非级别删除方式，如果当前流程如果并没有完成，则无法删除
        repositoryService.deleteDeployment(deploymentId, true);
    }

    /**
     * 下载资源文件
     * 方案1：使用Activity-7提供的API来下载资源文件
     * 方案2：自己写代码从数据库中下载文件；jdbc对blob类型，clob类型数据读取出来，保存到文件目录
     * 解决IO操作：commons-io.jar(apache基金会的工具包)
     * 这里我们使用方案1(推荐)，RepositoryService
     */
    @Test
    public void getDeployment() throws IOException {
//         1、得到引擎
        ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
//        2、获取api，RepositoryService
        RepositoryService repositoryService = processEngine.getRepositoryService();
//        3、获取查询对象 ProcessDefinitionQuery查询流程定义信息
        ProcessDefinition processDefinition = repositoryService.createProcessDefinitionQuery()
                .processDefinitionKey("myEvection")
                .singleResult();
//        4、通过流程定义信息，获取部署ID
        String deploymentId = processDefinition.getDeploymentId();
//        5、通过RepositoryService ，传递部署id参数，读取资源信息（png 和 bpmn）
//          5.1、获取png图片的流
//        从流程定义表中，获取png图片的目录和名字
        String pngName = processDefinition.getDiagramResourceName();
//        通过 部署id和 文件名字来获取图片的资源
        InputStream pngInput = repositoryService.getResourceAsStream(deploymentId, pngName);
//          5.2、获取bpmn的流
        String bpmnName = processDefinition.getResourceName();
        InputStream bpmnInput = repositoryService.getResourceAsStream(deploymentId, bpmnName);
//        6、构造OutputStream流
        File pngFile = new File("C:\\Users\\15713\\Desktop\\新建文件夹\\evectionflow01.png");
        File bpmnFile = new File("C:\\Users\\15713\\Desktop\\新建文件夹\\evectionflow01.bpmn");
        FileOutputStream pngOutStream = new FileOutputStream(pngFile);
        FileOutputStream bpmnOutStream = new FileOutputStream(bpmnFile);
//        7、输入流，输出流的转换
        IOUtils.copy(pngInput, pngOutStream);
        IOUtils.copy(bpmnInput, bpmnOutStream);
//        8、关闭流
        pngOutStream.close();
        bpmnOutStream.close();
        pngInput.close();
        bpmnInput.close();
    }

    /**
     * 查看历史信息
     */
    @Test
    public void findHistoryInfo() {
//      获取引擎
        ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
//        获取HistoryService
        HistoryService historyService = processEngine.getHistoryService();
//        获取 actinst表的查询对象
        HistoricActivityInstanceQuery instanceQuery = historyService.createHistoricActivityInstanceQuery();
//        查询 actinst表，条件：根据 InstanceId 查询
//        instanceQuery.processInstanceId("5001");
//        查询 ACT_HI_ACTINST表，条件：根据 DefinitionId 查询
        instanceQuery.processDefinitionId("myEvection:1:2504");
//        增加排序操作,orderByHistoricActivityInstanceStartTime 根据开始时间排序 asc 升序
        instanceQuery.orderByHistoricActivityInstanceStartTime().asc();
//        查询所有内容
        List<HistoricActivityInstance> activityInstanceList = instanceQuery.list();
//        输出
        //请记住CTRL+H快捷键
        for (HistoricActivityInstance hi : activityInstanceList) {
            System.out.println(hi.getActivityId());
            System.out.println(hi.getActivityName());
            System.out.println(hi.getProcessDefinitionId());
            System.out.println(hi.getProcessInstanceId());
            System.out.println("<==========================>");
        }
    }

}
